This example demonstrates how to map dwelling units by primary rensidence status and structural type for primary residences. ## Data First we grab the building data via cancensus, making use of the CensusMapper API tool to select the regions and variables we need.
#devtools::install_github("mountainmath/cancensus")
library(cancensus)
library(dotdensity)
# options(cancensus.api_key='your_api_key')
dataset='CA16'
regions=list(CSD="3520005")
vector_data <- search_census_vectors("structural type of dwelling",dataset) %>%
child_census_vectors(TRUE)
vectors <- vector_data %>% pull(vector)
We choose the categories and colours we want to map and define a convenience function to rename the variables and compute the qantities for the other asian countries that we don’t break out.
labels=list(v_CA16_417="Movable Dwelling",
v_CA16_409="Single Detached",
v_CA16_416="Other Single Attached",
v_CA16_414="Duplex",
v_CA16_412="Semi Detached",
v_CA16_413="Row House",
v_CA16_415="Apartment, < 5 storeys",
v_CA16_410="Apartment, >= 5 storeys")
categories=c("Non-primary Residence",as.character(labels))
colors=setNames(
c("#cccccc","#7a0177", "#ffff00", "#ffcc00", "#ff6600", "#ff0066", "#ff00ff", "#4dff4a", "#00ffff"),
categories)
prep_data <- function(geo){
data <- geo@data %>% replace(is.na(.), 0)
names(data)[names(data) %in% names(labels)] <- as.character(labels[names(data)[names(data) %in% names(labels)]])
data <- data %>%
mutate(`Non-primary Residence`=Dwellings - Households)
geo@data <- data
return(geo)
}
Next we grab the data via cancensus,
data_csd=get_census(dataset = dataset, regions=regions,vectors=vectors,geo_format='sp',labels='short',level='CSD') %>% prep_data
OGR data source with driver: GeoJSON
Source: "data_cache/CM_geo_d0c52f6e04a54d8daf08bfeb51a22159.geojson", layer: "OGRGeoJSON"
with 1 features
It has 11 fields
data_ct=get_census(dataset = dataset, regions=regions,vectors=vectors,geo_format='sp',labels='short',level='CT') %>% prep_data
OGR data source with driver: GeoJSON
Source: "data_cache/CM_geo_f8e7bafae9c5a7b33076dfc4ba182db3.geojson", layer: "OGRGeoJSON"
with 572 features
It has 11 fields
data_da=get_census(dataset = dataset, regions=regions,vectors=vectors,geo_format='sp',labels='short',level='DA') %>% prep_data
OGR data source with driver: GeoJSON
Source: "data_cache/CM_geo_f1e81fc534b1253bc9e70561e853ce5a.geojson", layer: "OGRGeoJSON"
with 3702 features
It has 10 fields
data_db=get_census(dataset = dataset, regions=regions,geo_format='sp',labels='short',level='DB')
OGR data source with driver: GeoJSON
Source: "data_cache/CM_geo_56d9a7d040f64a6a9bf50c93a44cfce3.geojson", layer: "OGRGeoJSON"
with 12622 features
It has 10 fields
which we then re-aggregate to make sure we don’t miss overall counts due to privacy cutoffs distribute them proportionally among the population.
data_ct@data <- dot_density.proportional_re_aggregate(data=data_ct@data,parent_data=data_csd@data,geo_match=setNames("GeoUID","CSD_UID"),categories=categories,base="Dwellings")
data_da@data <- dot_density.proportional_re_aggregate(data=data_da@data,parent_data=data_ct@data,geo_match=setNames("GeoUID","CT_UID"),categories=categories,base="Dwellings")
restarting interrupted promise evaluation
data_db@data <- dot_density.proportional_re_aggregate(data=data_db@data,parent_data=data_da@data,geo_match=setNames("GeoUID","DA_UID"),categories=categories,base="Dwellings")
Map
All that’s left to do is to covert our re-aggregated block-level data to dots, using the dot_density.compute_dots function from the dotdensity package and feed it into the dot_density.dots_map function to add them to our basemap.
# 1 dot = x dwelling units
scale=10
#dots.db <- dot_density.compute_dots(geo_data = data_db, categories = categories, scale=scale)
basemap +
# zoom in a bit
#coord_fixed(xlim=c(-123.29,-122.6), ylim=c(49.02,49.35), ratio = 1/cos(49.2/180*pi)) +
scale_colour_manual(values = colors) +
labs(color = "",
title="Dwelling Units 2016",
caption="Source: StatCan Census 2016 via cancensus & CensusMapper.ca",
subtitle = paste0("1 dot = ",scale," dwelling units")) +
dot_density.dots_map(dots=dots.db,alpha=0.9,size=0.25)

# save image for later
ggsave('../images/dwellings.png',width=26,height=26)
LS0tCnRpdGxlOiAiQnVpbGRpbmcgVHlwZXMiCmF1dGhvcjogIkplbnMgdm9uIEJlcmdtYW5uIgpkYXRlOiAiMjAxNy0wOC0zMCIKb3V0cHV0OiBodG1sX25vdGVib29rCnZpZ25ldHRlOiA+CiAgJVxWaWduZXR0ZUluZGV4RW50cnl7QnVpbGRpbmcgVHlwZXN9CiAgJVxWaWduZXR0ZUVuZ2luZXtrbml0cjo6cm1hcmtkb3dufQogICVcVmlnbmV0dGVFbmNvZGluZ3tVVEYtOH0KLS0tCgpUaGlzIGV4YW1wbGUgZGVtb25zdHJhdGVzIGhvdyB0byBtYXAgZHdlbGxpbmcgdW5pdHMgYnkgcHJpbWFyeSByZW5zaWRlbmNlIHN0YXR1cyBhbmQgc3RydWN0dXJhbCB0eXBlIGZvciBwcmltYXJ5IHJlc2lkZW5jZXMuCiMjIERhdGEKRmlyc3Qgd2UgZ3JhYiB0aGUgYnVpbGRpbmcgZGF0YSB2aWEgW2NhbmNlbnN1c10oaHR0cHM6Ly9naXRodWIuY29tL21vdW50YWluTWF0aC9jYW5jZW5zdXMpLCBtYWtpbmcgdXNlIG9mIHRoZSBbQ2Vuc3VzTWFwcGVyIEFQSSB0b29sXShodHRwczovL2NlbnN1c21hcHBlci5jYS9hcGkvQ0ExMSkgdG8gc2VsZWN0IHRoZSByZWdpb25zIGFuZCB2YXJpYWJsZXMgd2UgbmVlZC4KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoIm1vdW50YWlubWF0aC9jYW5jZW5zdXMiKQpsaWJyYXJ5KGNhbmNlbnN1cykKbGlicmFyeShkb3RkZW5zaXR5KQojIG9wdGlvbnMoY2FuY2Vuc3VzLmFwaV9rZXk9J3lvdXJfYXBpX2tleScpCmRhdGFzZXQ9J0NBMTYnCnJlZ2lvbnM9bGlzdChDU0Q9IjM1MjAwMDUiKQp2ZWN0b3JzIDwtIHNlYXJjaF9jZW5zdXNfdmVjdG9ycygic3RydWN0dXJhbCB0eXBlIG9mIGR3ZWxsaW5nIixkYXRhc2V0KSAlPiUKICBjaGlsZF9jZW5zdXNfdmVjdG9ycyhUUlVFKSAlPiUgIAogIHB1bGwodmVjdG9yKQpgYGAKCldlIGNob29zZSB0aGUgY2F0ZWdvcmllcyBhbmQgY29sb3VycyB3ZSB3YW50IHRvIG1hcCBhbmQgZGVmaW5lIGEgY29udmVuaWVuY2UgZnVuY3Rpb24gdG8gcmVuYW1lIHRoZSB2YXJpYWJsZXMgYW5kIGNvbXB1dGUgdGhlIHFhbnRpdGllcyBmb3IgdGhlIG90aGVyIGFzaWFuIGNvdW50cmllcyB0aGF0IHdlIGRvbid0IGJyZWFrIG91dC4KYGBge3J9CgpsYWJlbHM9bGlzdCh2X0NBMTZfNDE3PSJNb3ZhYmxlIER3ZWxsaW5nIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgIHZfQ0ExNl80MDk9IlNpbmdsZSBEZXRhY2hlZCIsCiAgICAgICAgICAgIHZfQ0ExNl80MTY9Ik90aGVyIFNpbmdsZSBBdHRhY2hlZCIsCiAgICAgICAgICAgIHZfQ0ExNl80MTQ9IkR1cGxleCIsCiAgICAgICAgICAgIHZfQ0ExNl80MTI9IlNlbWkgRGV0YWNoZWQiLAogICAgICAgICAgICB2X0NBMTZfNDEzPSJSb3cgSG91c2UiLAogICAgICAgICAgICB2X0NBMTZfNDE1PSJBcGFydG1lbnQsIDwgNSBzdG9yZXlzIiwKICAgICAgICAgICAgdl9DQTE2XzQxMD0iQXBhcnRtZW50LCA+PSA1IHN0b3JleXMiKQoKY2F0ZWdvcmllcz1jKCJOb24tcHJpbWFyeSBSZXNpZGVuY2UiLGFzLmNoYXJhY3RlcihsYWJlbHMpKQpjb2xvcnM9c2V0TmFtZXMoCiAgYygiI2NjY2NjYyIsIiM3YTAxNzciLCAiI2ZmZmYwMCIsICIjZmZjYzAwIiwgIiNmZjY2MDAiLCAiI2ZmMDA2NiIsICIjZmYwMGZmIiwgIiM0ZGZmNGEiLCAiIzAwZmZmZiIpLAogIGNhdGVnb3JpZXMpCgoKcHJlcF9kYXRhIDwtIGZ1bmN0aW9uKGdlbyl7CiAgZGF0YSA8LSBnZW9AZGF0YSAlPiUgcmVwbGFjZShpcy5uYSguKSwgMCkKICBuYW1lcyhkYXRhKVtuYW1lcyhkYXRhKSAlaW4lIG5hbWVzKGxhYmVscyldIDwtIGFzLmNoYXJhY3RlcihsYWJlbHNbbmFtZXMoZGF0YSlbbmFtZXMoZGF0YSkgJWluJSBuYW1lcyhsYWJlbHMpXV0pCiAgZGF0YSA8LSBkYXRhICU+JSAKICAgIG11dGF0ZShgTm9uLXByaW1hcnkgUmVzaWRlbmNlYD1Ed2VsbGluZ3MgLSBIb3VzZWhvbGRzKQogIGdlb0BkYXRhIDwtIGRhdGEKICByZXR1cm4oZ2VvKQp9CmBgYAoKCk5leHQgd2UgZ3JhYiB0aGUgZGF0YSB2aWEgYGNhbmNlbnN1c2AsCmBgYHtyLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdGFfY3NkPWdldF9jZW5zdXMoZGF0YXNldCA9IGRhdGFzZXQsIHJlZ2lvbnM9cmVnaW9ucyx2ZWN0b3JzPXZlY3RvcnMsZ2VvX2Zvcm1hdD0nc3AnLGxhYmVscz0nc2hvcnQnLGxldmVsPSdDU0QnKSAlPiUgcHJlcF9kYXRhCmRhdGFfY3Q9Z2V0X2NlbnN1cyhkYXRhc2V0ID0gZGF0YXNldCwgcmVnaW9ucz1yZWdpb25zLHZlY3RvcnM9dmVjdG9ycyxnZW9fZm9ybWF0PSdzcCcsbGFiZWxzPSdzaG9ydCcsbGV2ZWw9J0NUJykgJT4lIHByZXBfZGF0YQpkYXRhX2RhPWdldF9jZW5zdXMoZGF0YXNldCA9IGRhdGFzZXQsIHJlZ2lvbnM9cmVnaW9ucyx2ZWN0b3JzPXZlY3RvcnMsZ2VvX2Zvcm1hdD0nc3AnLGxhYmVscz0nc2hvcnQnLGxldmVsPSdEQScpICU+JSBwcmVwX2RhdGEKZGF0YV9kYj1nZXRfY2Vuc3VzKGRhdGFzZXQgPSBkYXRhc2V0LCByZWdpb25zPXJlZ2lvbnMsZ2VvX2Zvcm1hdD0nc3AnLGxhYmVscz0nc2hvcnQnLGxldmVsPSdEQicpCmBgYAoKd2hpY2ggd2UgdGhlbiByZS1hZ2dyZWdhdGUgdG8gbWFrZSBzdXJlIHdlIGRvbid0IG1pc3Mgb3ZlcmFsbCBjb3VudHMgZHVlIHRvIHByaXZhY3kgY3V0b2ZmcyBkaXN0cmlidXRlIHRoZW0KcHJvcG9ydGlvbmFsbHkgYW1vbmcgdGhlIHBvcHVsYXRpb24uCmBgYHtyfQpkYXRhX2N0QGRhdGEgPC0gZG90X2RlbnNpdHkucHJvcG9ydGlvbmFsX3JlX2FnZ3JlZ2F0ZShkYXRhPWRhdGFfY3RAZGF0YSxwYXJlbnRfZGF0YT1kYXRhX2NzZEBkYXRhLGdlb19tYXRjaD1zZXROYW1lcygiR2VvVUlEIiwiQ1NEX1VJRCIpLGNhdGVnb3JpZXM9Y2F0ZWdvcmllcyxiYXNlPSJEd2VsbGluZ3MiKQpkYXRhX2RhQGRhdGEgPC0gZG90X2RlbnNpdHkucHJvcG9ydGlvbmFsX3JlX2FnZ3JlZ2F0ZShkYXRhPWRhdGFfZGFAZGF0YSxwYXJlbnRfZGF0YT1kYXRhX2N0QGRhdGEsZ2VvX21hdGNoPXNldE5hbWVzKCJHZW9VSUQiLCJDVF9VSUQiKSxjYXRlZ29yaWVzPWNhdGVnb3JpZXMsYmFzZT0iRHdlbGxpbmdzIikKZGF0YV9kYkBkYXRhIDwtIGRvdF9kZW5zaXR5LnByb3BvcnRpb25hbF9yZV9hZ2dyZWdhdGUoZGF0YT1kYXRhX2RiQGRhdGEscGFyZW50X2RhdGE9ZGF0YV9kYUBkYXRhLGdlb19tYXRjaD1zZXROYW1lcygiR2VvVUlEIiwiREFfVUlEIiksY2F0ZWdvcmllcz1jYXRlZ29yaWVzLGJhc2U9IkR3ZWxsaW5ncyIpCmBgYAoKCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGdncGxvdDIpCmJnX2NvbG9yPSIjNDQ0NDQ0IgpiYXNlX2NvbG9yPSIjMTExMTExIgp0ZXh0X2NvbG9yPSIjZWVlZWVlIgp0aGVtZV9vcHRzPC1saXN0KHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBiZ19jb2xvciwgY29sb3VyID0gTkEpLAogICAgICAgICAgICAgICAgICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPWJnX2NvbG9yLCBzaXplPTEsbGluZXR5cGU9InNvbGlkIixjb2xvcj10ZXh0X2NvbG9yKSwKICAgICAgICAgICAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04MCxoanVzdCA9IDAuNSwgY29sb3I9dGV4dF9jb2xvciksCiAgICAgICAgICAgICAgICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTYwLGhqdXN0ID0gMC41LCBjb2xvcj10ZXh0X2NvbG9yKSwKICAgICAgICAgICAgICAgICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZT0yNSwgY29sb3I9dGV4dF9jb2xvciksCiAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NDAsIGNvbG9yPXRleHRfY29sb3IpLAogICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MzAsIGNvbG9yPXRleHRfY29sb3IpLAogICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9YmdfY29sb3IsIHNpemU9MSxsaW5ldHlwZT0ic29saWQiLGNvbG9yPWJnX2NvbG9yKSwKICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGZpbGwgPSBiZ19jb2xvcixjb2xvciA9IGJnX2NvbG9yKSwKICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgzLCAnbGluZXMnKSwKICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikpCgpiYXNlbWFwIDwtICAgZ2dwbG90KGRhdGFfY3NkKSArCiAgICBnZW9tX3BvbHlnb24oYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBncm91cCksIGZpbGwgPSBiYXNlX2NvbG9yLCBzaXplPTAuMSwgY29sb3IgPSAnZ3JleScpICsKICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQobnJvdz0yLG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT0xNSkpKSArCiAgICAjY29vcmRfbWFwKHByb2plY3Rpb249ImxhbWJlcnQiLCBsYXQwPTQ5LCBsYXQ9NDkuNCkgKwogICAgdGhlbWVfb3B0cwoKYGBgCgoKIyNNYXAKQWxsIHRoYXQncyBsZWZ0IHRvIGRvIGlzIHRvIGNvdmVydCBvdXIgcmUtYWdncmVnYXRlZCBibG9jay1sZXZlbCBkYXRhIHRvIGRvdHMsIHVzaW5nIHRoZSBgZG90X2RlbnNpdHkuY29tcHV0ZV9kb3RzYApmdW5jdGlvbiBmcm9tIHRoZSBbYGRvdGRlbnNpdHlgIHBhY2thZ2VdKCkgYW5kIGZlZWQgaXQgaW50byB0aGUgYGRvdF9kZW5zaXR5LmRvdHNfbWFwYCBmdW5jdGlvbiB0byBhZGQgdGhlbSB0bwpvdXIgYmFzZW1hcC4KYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMywgbWVzc2FnZT1UUlVFLCB3YXJuaW5nPVRSVUV9CiMgMSBkb3QgPSB4IGR3ZWxsaW5nIHVuaXRzCnNjYWxlPTEwCgoKI2RvdHMuZGIgPC0gZG90X2RlbnNpdHkuY29tcHV0ZV9kb3RzKGdlb19kYXRhID0gZGF0YV9kYiwgY2F0ZWdvcmllcyA9IGNhdGVnb3JpZXMsIHNjYWxlPXNjYWxlKQpiYXNlbWFwICsKICAjIHpvb20gaW4gYSBiaXQKICAjY29vcmRfZml4ZWQoeGxpbT1jKC0xMjMuMjksLTEyMi42KSwgeWxpbT1jKDQ5LjAyLDQ5LjM1KSwgcmF0aW8gPSAxL2Nvcyg0OS4yLzE4MCpwaSkpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbG9ycykgKwogIGxhYnMoY29sb3IgPSAiIiwKICAgICAgICAgICAgICAgIHRpdGxlPSJEd2VsbGluZyBVbml0cyAyMDE2IiwKICAgICAgICAgICAgICAgIGNhcHRpb249IlNvdXJjZTogU3RhdENhbiBDZW5zdXMgMjAxNiB2aWEgY2FuY2Vuc3VzICYgQ2Vuc3VzTWFwcGVyLmNhIiwKICAgICAgICAgICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKCIxIGRvdCA9ICIsc2NhbGUsIiBkd2VsbGluZyB1bml0cyIpKSArIAogIGRvdF9kZW5zaXR5LmRvdHNfbWFwKGRvdHM9ZG90cy5kYixhbHBoYT0wLjksc2l6ZT0wLjI1KQoKIyBzYXZlIGltYWdlIGZvciBsYXRlcgpnZ3NhdmUoJy4uL2ltYWdlcy9kd2VsbGluZ3MucG5nJyx3aWR0aD0yNixoZWlnaHQ9MjYpCmBgYAoK